home *** CD-ROM | disk | FTP | other *** search
/ The Utilities Experience / The Utilities Experience - Volume 1.iso / software / misc / o-z / x-windows / gs262 / gs.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-12-22  |  14.4 KB  |  540 lines

  1. /* Copyright (C) 1989, 1992, 1993 Aladdin Enterprises.  All rights reserved.
  2.  
  3. This file is part of Ghostscript.
  4.  
  5. Ghostscript is distributed in the hope that it will be useful, but
  6. WITHOUT ANY WARRANTY.  No author or distributor accepts responsibility
  7. to anyone for the consequences of using it or for whether it serves any
  8. particular purpose or works at all, unless he says so in writing.  Refer
  9. to the Ghostscript General Public License for full details.
  10.  
  11. Everyone is granted permission to copy, modify and redistribute
  12. Ghostscript, but only under the conditions described in the Ghostscript
  13. General Public License.  A copy of this license is supposed to have been
  14. given to you along with Ghostscript so you can know your rights and
  15. responsibilities.  It should be in a file named COPYING.  Among other
  16. things, the copyright notice and this notice must be preserved on all
  17. copies.  */
  18.  
  19. #ifdef AMIGA
  20. const char versionstring[]="$VER: ghostscript 2.6.2 (18.11.95)";
  21. #endif
  22.  
  23. /* gs.c */
  24. /* Driver program for Ghostscript */
  25. /* Define PROGRAM_NAME before we include std.h */
  26. #define PROGRAM_NAME gs_product
  27. #include "ctype_.h"
  28. #include "memory_.h"
  29. #include "string_.h"
  30. /* Capture stdin/out/err before gs.h redefines them. */
  31. #include <stdio.h>
  32. static FILE *real_stdin, *real_stdout, *real_stderr;
  33. static void
  34. get_real(void)
  35. {    real_stdin = stdin, real_stdout = stdout, real_stderr = stderr;
  36. }
  37. #include "ghost.h"
  38. #include "gxdevice.h"
  39. #include "gxdevmem.h"
  40. #include "stream.h"
  41. #include "alloc.h"
  42. #include "errors.h"
  43. #include "estack.h"
  44. #include "iscan.h"
  45. #include "main.h"
  46. #include "ostack.h"
  47. #include "store.h"
  48. #include "files.h"                /* requires stream.h */
  49.  
  50. #if defined(NOSTDERR) && defined(__SASC)
  51. #include <unistd.h>
  52. #include <signal.h>
  53. void xgs_exit(int signo)
  54. {
  55.     gs_exit(0);
  56. }
  57. #endif
  58.   
  59. #ifndef GS_LIB
  60. #  define GS_LIB "GS_LIB"
  61. #endif
  62.  
  63. #ifndef GS_OPTIONS
  64. #  define GS_OPTIONS "GS_OPTIONS"
  65. #endif
  66.  
  67. /* Library routines not declared in a standard header */
  68. extern char *getenv(P1(const char *));
  69. /* Note: sscanf incorrectly defines its first argument as char * */
  70. /* rather than const char *.  This accounts for the ugly casts below. */
  71.  
  72. /* Device procedures imported from gsdevice.c. */
  73. extern gx_device *gs_getdevice(P1(int));
  74. extern char *gs_devicename(P1(gx_device *));
  75.  
  76. /* Other imported data */
  77. extern int gs_alloc_debug;
  78. extern int gs_log_errors;
  79. extern gx_device *gx_device_list[];
  80. extern const char *gs_copyright;
  81. extern const int gs_revision;
  82. extern const long gs_revisiondate;
  83.  
  84. /*
  85.  * Help strings.  We have to break them up into parts, because
  86.  * the Watcom compiler has a limit of 510 characters for a single token.
  87.  * For PC displays, we want to limit the strings to 24 lines.
  88.  */
  89. private const char *gs_help1 = "\
  90. Usage: gs [switches] [file1.ps file2.ps ...]\n\
  91. Available devices:";
  92. private const char *gs_help2a = "\n\
  93. Most frequently used switches: (you can use # in place of =)\n\
  94.     @<file>              treat file like part of the command line\n\
  95.                            (to get around DOS command line limit)\n\
  96.     -d<name>[=<token>]   define name as token, or null if no token given\n\
  97.     -f<file>             read this file even if its name begins with - or @\n\
  98.     -g<width>x<height>   set width and height (`geometry'), in pixels\n\
  99.     -I<prefix>           add prefix to search path\n";
  100. private const char *gs_help2b = "\
  101.     -q                   `quiet' mode, suppress most messages\n\
  102.     -r<res>              set resolution, in pixels per inch\n\
  103.     -s<name>=<string>    define name as string\n\
  104.     -sDEVICE=<devname>   select initial device\n\
  105.     -sOutputFile=<file>  select output file: embed %d for page #,\n\
  106.                            - means stdout, use |command to pipe\n\
  107. `-' alone as a file name means read from stdin non-interactively.\n\
  108. For more complete information, please read the use.doc file.\n";
  109.  
  110. /* Forward references */
  111. private int swproc(P1(const char *));
  112. private void argproc(P1(const char *));
  113. private void cmdproc(P4(const char *, int, char *, int));
  114. private void print_revision(P0());
  115. private int esc_strlen(P1(const char *));
  116. private void esc_strcat(P2(char *, const char *));
  117. private void runarg(P4(const char **, const char *, const char *, int));
  118. private void run_string(P1(const char *));
  119.  
  120. #ifdef AMIGA
  121. /* External references */
  122. extern void initial_enter_name(const char *, ref *);
  123. extern void initial_enter_string(const char *, uint, ref *);
  124. extern int zflush(register os_ptr);
  125. extern int zflushpage(register os_ptr);
  126. #endif
  127.  
  128. /* Parameters set by swproc */
  129. private int quiet;
  130. private int batch;
  131.  
  132. main(int argc, const char *argv[])
  133. {    int argi;
  134.     char cstr[128];
  135. #if defined(NOSTDERR) && defined(__SASC)
  136.     dup2(1,2);
  137.     signal(SIGINT, xgs_exit);
  138.     signal(SIGQUIT, xgs_exit);
  139. #endif
  140.     get_real();
  141.     gs_init0(real_stdin, real_stdout, real_stderr, argc);
  142.        {    char *lib = getenv(GS_LIB);
  143.         if ( lib != 0 ) 
  144.            {    int len = strlen(lib);
  145.             gs_lib_env_path = gs_malloc(len + 1, 1, "GS_LIB");
  146.             strcpy(gs_lib_env_path, lib);
  147.            }
  148.        }
  149.     /* Execute files named in the command line, */
  150.     /* processing options along the way. */
  151.     /* Wait until the first file name (or the end */
  152.     /* of the line) to finish initialization. */
  153.     batch = 0;
  154.     quiet = 0;
  155.     /* If debugging is enabled, trace the device calls. */
  156. #ifdef DEBUG
  157.        {    extern gx_device *gs_trace_device(P1(gx_device *));
  158.         extern const gx_device_memory
  159.             mem_mono_device, mem_mapped2_color_device,
  160.             mem_mapped4_color_device, mem_mapped8_color_device,
  161.             mem_true16_color_device,
  162.             mem_true24_color_device, mem_true32_color_device;
  163.         static const gx_device_memory *mdevs[8] =
  164.            {    &mem_mono_device, &mem_mapped2_color_device,
  165.             &mem_mapped4_color_device, &mem_mapped8_color_device,
  166.             &mem_true16_color_device,
  167.             &mem_true24_color_device, &mem_true32_color_device,
  168.             0
  169.            };
  170.         gx_device **pdevs[3];
  171.         gx_device ***ppdev;
  172.         gx_device **pdev;
  173.         pdevs[0] = gx_device_list;
  174.         pdevs[1] = (gx_device **)mdevs;
  175.         pdevs[2] = 0;
  176.         for ( ppdev = pdevs; *ppdev != 0; ppdev++ )
  177.          for ( pdev = *ppdev; *pdev != 0; pdev++ )
  178.            {
  179. /******
  180.             gx_device *tdev;
  181.             gx_device_complete_procs(*pdev);
  182.             tdev = gs_trace_device(*pdev);
  183.             if ( tdev == 0 )
  184.                {    lprintf("Can't allocate traced device!\n");
  185.                 gs_exit(1);
  186.                }
  187.             *pdev = tdev;
  188.  ******/
  189.            }
  190.        }
  191. #endif
  192.     {    const char *opts = getenv(GS_OPTIONS);
  193.         if ( opts != 0 ) cmdproc(opts, 0, cstr, sizeof(cstr));
  194.     }
  195.     for ( argi = 1; argi < argc; argi++ )
  196.        {    const char **argp = &argv[argi];
  197.         const char *arg = *argp;
  198.         switch ( *arg )
  199.         {
  200.         case '@':
  201.             cmdproc(arg + 1, 1, cstr, sizeof(cstr));
  202.             break;
  203.         case '-':
  204.             if ( !strcmp(arg, "--") || !strcmp(arg, "-+") )
  205.             {    /* run with command line args */
  206.                 int nstrs = argc - argi - 2;
  207.                 if ( nstrs < 0 )    /* no file to run! */
  208.                 {    puts("Usage: gs ... -- file.ps arg1 ... argn");
  209.                     gs_exit(1);
  210.                 }
  211.                 runarg(argp + 1, "{userdict /ARGUMENTS [", "] put ", nstrs);
  212.                 gs_exit(0);
  213.             }
  214.             else
  215.             {    if ( swproc(arg) < 0 )
  216.                   fprintf(stdout, "Unknown switch %s - ignoring\n", arg);
  217.             }
  218.             break;
  219.         default:
  220.             argproc(arg);
  221.         }
  222.        }
  223.     gs_init2();
  224.     if ( !batch )
  225.         run_string("systemdict /start get exec");
  226.     gs_exit(0);
  227. }
  228.  
  229. /* Process switches */
  230. private int
  231. swproc(const char *arg)
  232. {    char sw = arg[1];
  233.     arg += 2;        /* skip - and letter */
  234.     switch ( sw )
  235.        {
  236.     default:
  237.         return -1;
  238.     case 0:                /* read stdin as a file */
  239.         batch = 1;
  240.         /* Set NOPAUSE so showpage won't try to read from stdin. */
  241.         swproc("-dNOPAUSE=true");
  242.         gs_init2();        /* Finish initialization */
  243.         run_string("(%stdin) (r) file cvx execute0");
  244.         break;
  245.     case 'A':            /* trace allocator */
  246.         gs_alloc_debug = 1; break;
  247.     case 'e':            /* log errors */
  248.         gs_log_errors = 1; break;
  249.     case 'E':            /* log errors */
  250.         gs_log_errors = 2; break;
  251.     case 'f':            /* run file of arbitrary name */
  252.         if ( *arg != 0 )
  253.             argproc(arg);
  254.         break;
  255.     case 'h':            /* print help */
  256.     case '?':            /* ditto */
  257.         print_revision();
  258.         fputs(gs_help1, stdout);
  259.            {    int i;
  260.             gx_device *pdev;
  261.             for ( i = 0; (pdev = gs_getdevice(i)) != 0; i++ )
  262.                 fprintf(stdout, (i & 7 ? " %s" : "\n    %s"),
  263.                     gs_devicename(pdev));
  264.            }
  265.         fputs(gs_help2a, stdout);
  266.         fputs(gs_help2b, stdout);
  267.         gs_exit(0);
  268.     case 'I':            /* specify search path */
  269.         gs_add_lib_path(arg);
  270.         break;
  271.     case 'q':            /* quiet startup */
  272.        {    ref vtrue;
  273.         quiet = 1;
  274.         gs_init1();
  275.         make_true(&vtrue);
  276.         initial_enter_name("QUIET", &vtrue);
  277.        }    break;
  278.     case 'D':            /* define name */
  279.     case 'd':
  280.     case 'S':            /* define name as string */
  281.     case 's':
  282.        {    const char *eqp = strchr(arg, '=');
  283.         uint nlen;
  284.         int isd = (sw == 'D' || sw == 'd');
  285.         ref value;
  286.         if ( eqp == NULL ) eqp = strchr(arg, '#');
  287.         /* Initialize the object memory, scanner, and */
  288.         /* name table now if needed. */
  289.         gs_init1();
  290.         if ( eqp == arg )
  291.            {    puts("Usage: -dname, -dname=token, -sname=string");
  292.             gs_exit(1);
  293.            }
  294.         if ( eqp == NULL )
  295.            {    if ( isd ) make_null(&value);
  296.             else make_string(&value, a_readonly, 0, (byte *)"");
  297.             nlen = strlen(arg);
  298.            }
  299.         else
  300.            {    int code;
  301.             nlen = eqp - arg;
  302.             eqp++;
  303.             if ( isd )
  304.                {    stream astream;
  305.                 sread_string(&astream,
  306.                          (const byte *)eqp, strlen(eqp));
  307.                 code = scan_token(&astream, 0, &value);
  308.                 if ( code )
  309.                    {    puts("-dname= must be followed by a valid token");
  310.                     gs_exit(1);
  311.                    }
  312.                }
  313.             else
  314.                {    int len = strlen(eqp);
  315.                 char *str = gs_malloc((uint)len, 1, "-s");
  316.                 if ( str == 0 )
  317.                    {    lprintf("Out of memory!\n");
  318.                     gs_exit(1);
  319.                    }
  320.                 memcpy(str, eqp, len);
  321.                 make_const_string(&value, a_readonly, len, (const byte *)str);
  322.                }
  323.            }
  324.         /* Enter the name in systemdict. */
  325.         initial_enter_string(arg, nlen, &value);
  326.         break;
  327.        }
  328.     case 'g':            /* define device geometry */
  329.        {    long width, height;
  330.         ref value;
  331.         gs_init1();
  332.         if ( sscanf((char *)arg, "%ldx%ld", &width, &height) != 2 )
  333.            {    puts("-g must be followed by <width>x<height>");
  334.             gs_exit(1);
  335.            }
  336.         make_int(&value, width);
  337.         initial_enter_name("DEVICEWIDTH", &value);
  338.         make_int(&value, height);
  339.         initial_enter_name("DEVICEHEIGHT", &value);
  340.         break;
  341.        }
  342.     case 'M':            /* set memory allocation increment */
  343.        {    unsigned msize = 0;
  344.         sscanf((char *)arg, "%d", &msize);
  345.         if ( msize <= 0 || msize >= 64 )
  346.            {    puts("-M must be between 1 and 63");
  347.             gs_exit(1);
  348.            }
  349.         gs_memory_chunk_size = msize << 10;
  350.        }
  351.         break;
  352.     case 'r':            /* define device resolution */
  353.        {    float xres, yres;
  354.         ref value;
  355.         gs_init1();
  356.         switch ( sscanf((char *)arg, "%fx%f", &xres, &yres) )
  357.            {
  358.         default:
  359.             puts("-r must be followed by <res> or <xres>x<yres>");
  360.             gs_exit(1);
  361.         case 1:            /* -r<res> */
  362.             yres = xres;
  363.         case 2:            /* -r<xres>x<yres> */
  364.             make_real(&value, xres);
  365.             initial_enter_name("DEVICEXRESOLUTION", &value);
  366.             make_real(&value, yres);
  367.             initial_enter_name("DEVICEYRESOLUTION", &value);
  368.            }
  369.         break;
  370.        }
  371.     case 'v':            /* print revision */
  372.         print_revision();
  373.         gs_exit(0);
  374.     case 'Z':
  375.         if ( !*arg )
  376.            {    /* No options, set all flags */
  377.             memset(gs_debug, 0xff, 128);
  378.            }
  379.         else
  380.            {    while ( *arg )
  381.                 gs_debug[*arg++ & 127] = 0xff;
  382.            }
  383.         break;
  384.        }
  385.     return 0;
  386. }
  387.  
  388. /* Define versions of strlen and strcat that encode strings in hex. */
  389. /* This is so we can enter escaped characters regardless of whether */
  390. /* the Level 1 convention of ignoring \s in strings-within-strings */
  391. /* is being observed (sigh). */
  392. private int
  393. esc_strlen(const char *str)
  394. #ifndef AMIGA
  395. {    return strlen(str) * 2 + 2;
  396. #else
  397. {    return ((int)strlen(str) * 2 + 2);
  398. #endif
  399. }
  400. private void
  401. esc_strcat(char *dest, const char *src)
  402. {    char *d = dest + strlen(dest);
  403.     const char *p;
  404.     static const char *hex = "0123456789abcdef";
  405.     *d++ = '<';
  406.     for ( p = src; *p; p++ )
  407.     {    byte c = (byte)*p;
  408.         *d++ = hex[c >> 4];
  409.         *d++ = hex[c & 0xf];
  410.     }
  411.     *d++ = '>';
  412.     *d = 0;
  413. }
  414.  
  415. /* Process file names */
  416. private void
  417. argproc(const char *arg)
  418. {    runarg(&arg, "{", "", 0);
  419. }
  420. private void
  421. runarg(const char **argp, const char *pre, const char *post, int nstrs)
  422. {    const char *arg = *argp;
  423.     static const char *pex = "run}execute";
  424.     int len = strlen(pre) + esc_strlen(arg) + strlen(post) + strlen(pex) + 1;
  425.     char *line;
  426.     int i;
  427.     for ( i = 1; i <= nstrs; i++ )
  428.         len += esc_strlen(argp[i]);
  429.     gs_init2();    /* Finish initialization */
  430.     line = gs_malloc(len, 1, "argproc");
  431.     if ( line == 0 )
  432.     {    lprintf("Out of memory!\n");
  433.         gs_exit(1);
  434.     }
  435.     strcpy(line, pre);
  436.     for ( i = 1; i <= nstrs; i++ )
  437.         esc_strcat(line, argp[i]);
  438.     strcat(line, post);
  439.     esc_strcat(line, arg);
  440.     strcat(line, pex);
  441.     run_string(line);
  442. }
  443. private void
  444. run_string(const char *str)
  445. {    int exit_code;
  446.     ref error_object;
  447.     int code = gs_run_string(str, gs_user_errors, &exit_code, &error_object);
  448.     zflush((ref *)0);    /* flush stdout */
  449.     zflushpage((ref *)0); /* force display update */
  450.     switch ( code )
  451.     {
  452.     case 0:
  453.         break;
  454.     case e_Quit:
  455.         gs_exit(0);
  456.     case e_Fatal:
  457.         eprintf1("Unrecoverable error, exit code %d\n", exit_code);
  458.         gs_exit(exit_code);
  459.     default:
  460.         gs_debug_dump_stack(code, &error_object);
  461.         gs_exit_with_code(255, code);
  462.     }
  463. }
  464.  
  465. /* Process command line indirection. */
  466. /* is_file is needed because the standard C library doesn't */
  467. /* provide a reasonable stream package that unifies files and strings. */
  468. private void
  469. cmdproc(const char *arg, int is_file, char *cstr, int cstr_max)
  470. {    FILE *f;
  471.     int endc;
  472.     if ( is_file )
  473.     {    strcpy(cstr, arg);
  474.         gs_set_lib_paths();
  475.         f = lib_fopen(cstr);
  476.         if ( f == NULL )
  477.         {    fprintf(stdout, "Unable to open command line file %s\n", arg);
  478.             gs_exit(1);
  479.         }
  480.         endc = EOF;
  481.     }
  482.     else
  483.     {    f = NULL;
  484.         endc = 0;
  485.     }
  486. #define cfsgetc() (f == NULL ? (*arg ? *arg++ : 0) : fgetc(f))
  487.     while ( 1 )
  488.     {    register int c;
  489.         register int i;
  490.         while ( isspace(c = cfsgetc()) ) ;
  491.         if ( c == endc ) break;
  492.         for ( i = 0; ; )
  493.         {    if ( i == cstr_max - 1 )
  494.             {    cstr[i] = 0;
  495.                 fprintf(stdout, "Command too long: %s\n", cstr);
  496.                 gs_exit(1);
  497.             }
  498.             cstr[i++] = c;
  499.             c = cfsgetc();
  500.             if ( c == endc || isspace(c) )
  501.                 break;
  502.         }
  503.         cstr[i] = 0;
  504.         switch ( cstr[0] )
  505.         {
  506.         case '@':
  507.             cmdproc(cstr + 1, 1, cstr, cstr_max);
  508.             break;
  509.         case '-':
  510.         {    /* swproc wants strings to be in the heap! */
  511.             char *sstr = gs_malloc(i + 1, 1, "cfsproc");
  512.             if ( sstr == 0 )
  513.             {    lprintf("Out of memory!\n");
  514.                 gs_exit(1);
  515.             }
  516.             strcpy(sstr, cstr);
  517.             if ( swproc(sstr) < 0 )
  518.               fprintf(stdout, "Unknown switch %s - ignoring\n", sstr);
  519.         }
  520.             break;
  521.         default:
  522.             argproc(cstr);
  523.         }
  524.     }
  525.     if ( is_file )
  526.         fclose(f);
  527. }
  528.  
  529. /* Print the revision and revision date. */
  530. private void
  531. print_revision(void)
  532. {    fprintf(stdout,
  533.         "%s version %d.%d.%d (%d/%d/%d)\n%s",
  534.         gs_product,
  535.         gs_revision / 100, (gs_revision / 10) % 10, gs_revision % 10,
  536.         (int)(gs_revisiondate / 100 % 100),
  537.         (int)(gs_revisiondate % 100), (int)(gs_revisiondate / 10000),
  538.         gs_copyright);
  539. }
  540.